/*
 * CalibratedMapBrowser.java
 *
 * Created on 29 avril 2007, 21:54
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package courselog.maputils;

import courselog.ImageBrowser;
import courselog.gpsutils.GeoDirection;
import courselog.gpsutils.PositionTracer;
import ewe.fx.Color;
import ewe.fx.Graphics;
import ewe.fx.IImage;
import ewe.fx.Image;
import ewe.fx.Pen;
import ewe.fx.Point;
import ewe.sys.mThread;
import ewe.ui.Form;
import ewe.ui.Gui;
import ewe.ui.KeyEvent;
import ewe.ui.MessageBox;

/**
 *
 * @author rigal
 */
public class CalibratedMapBrowser extends ImageBrowser {
    
    /** X values of polygon drawing a reference point.
     */
    public static final int[] tXPt=new int[]{0,5,3,5,-5,-3,-5,0,2,0,-2,2,0,-2,0};
    
    /** Y values of polygon drawing a reference point.
     */
    public static final int[] tYPt=new int[]{0,2,0,-2,2,0,-2,0,5,3,5,-5,-3,-5,0};
    
    /** X values of polygon drawing a reference point computed position.
     */
    public static final int[] tXPt2=new int[]{0,5,3,3,-3,-3,-5,0,5,3,3,-3,-3,-5,0};
    
    /** Y values of polygon drawing a reference point computed position.
     */
    public static final int[] tYPt2=new int[]{0,3,3,5,-5,-3,-3,0,-3,-3,-5,5,3,3,0};
    
    /** stateReferenceDisplay value if points are not displayed.
     */
    public static final int STATE_NODISPLAY=0;
    
    /** stateReferenceDisplay value if points only are displayed.
     */
    public static final int STATE_DISPLAYSIMPLE=1;
    
    /** stateReferenceDisplay value if points are displayed and
     *  computed values are displayed too.
     */
    public static final int STATE_DISPLAYDOUBLE=2;
    
    /** Check if the map was modified. */
    public boolean isMapModified=false;
    
    /** My CalibratedMap */
    public CalibratedMap cmMyMap=null;
    
    /** Status to display reference points or not */
    public int stateReferenceDisplay=STATE_DISPLAYSIMPLE;
    
    /** Pen for normal drawing of points.
     */
    public static final Pen NORMALPEN=new Pen(Color.MediumBlue,Pen.SOLID,1);
    
    /** Pen for dual drawing of points.
     */
    public static final Pen DUALPEN=new Pen(new Color(240,50,50),Pen.SOLID,1);
    
    /**
     * Current drawing pen.
     */
    public Pen currentPen=NORMALPEN;
    
//    /**
//     * temporary transformation data.
//     */
//    public double[] tTr=null; <<< not supported on WinCE
    
    /**
     * temporary point object.
     */
    public Point tmpPt=null;
    
    /**
     * temporary Direction object.
     */
    public GeoDirection tmpGD=null;
    
    /** My reference point entry dialog. */
    public MapReferencePointDialog myDlg=null;
    
    // Constructors
    
    /** Creates a new empty instance of CalibratedMapBrowser */
    public CalibratedMapBrowser(PositionTracer pT) {
        isReticuleOn=true;
        getMyDlg().setMyPositionTracer(pT);
    }
    
    /**
     * Creates a new instance of CalibratedMapBrowser from an image file name.
     */
//    public CalibratedMapBrowser(String imgFileName) {
//        isReticuleOn=true;
//        cmMyMap= new CalibratedMap(imgFileName);
//        isMapModified=false;
//        stateReferenceDisplay=STATE_DISPLAYSIMPLE;
//        setBaseImage(cmMyMap.getImageMap());
//        updateDisplayedImage();
//    }
    
    // ACCESSORS
        
    /**
     * Get current dialog.
     */
    public MapReferencePointDialog getMyDlg() {
        if(myDlg==null) {
            myDlg=new MapReferencePointDialog(this.parent);
        }
        return myDlg;
    }
    // Class methods
    
    /**
     * Set Calibrated map.
     */
    public void setCalibratedMapFrom(String imageFileName, Image img) {
        if(cmMyMap!=null) cmMyMap.free();
        cmMyMap = new CalibratedMap(imageFileName);
        cmMyMap.setImageMap(img);
        isMapModified=false;
        stateReferenceDisplay=STATE_DISPLAYSIMPLE;
        setBaseImage(cmMyMap.getImageMap());
        updateDisplayedImage();
    }
    
    /**
     * Re-center Calibrated map.
     */
    public void reCenter() {
        setBaseImage(this.baseImageData,this.baseIImage);
        updateDisplayedImage();
    }
    
    /**
     * Try to delete closer reference point to the selected one.
     */
    public void tryDeleteReferencepoint(Point p) {
        IImage img=cmMyMap.getImageMap();
        if(img==null) return;
        MapReferencePoint mp=cmMyMap.findClosestReferencepoint(p,
                (double) (cmMyMap.imgW+cmMyMap.imgH)/20.0d);
        if(mp==null) return;
        MessageBox mb=new MessageBox("Delete point",
                "Delete this point?\n x="+mp.iX+",y="+mp.iY,
                MessageBox.MBYESNO);
        //mb.setLocation()
        int resDlg=mb.execute(this.getFrame(),Gui.CENTER_FRAME);
        if(resDlg!=MessageBox.IDYES) return;
        cmMyMap.vRefPoints.remove(mp);
        if(cmMyMap.vRefPoints.size()<2) stateReferenceDisplay=STATE_DISPLAYSIMPLE;
        isMapModified=true;
        updateDisplayedImage();
    }
    
    /**
     * Draw a point position.
     */
    public void drawRefPointSymbolAt(Image dest, int x, int y) {
        drawRefPointSymbolAt(dest,x,y,false);
    }
    
    /**
     * Draw a point position.
     */
    public void drawRefPointSymbolAt(Image dest, int x, int y, boolean rotByPI_4) {
        Graphics gD=new Graphics(dest);
        gD.setPen(currentPen);
//        gD.setDrawOp(Graphics.DRAW_XOR);
//        if(rotByPI_4) {
//            if(tTr==null) {
//                tTr=new double[6];
//                tTr[0]=Math.cos(Math.PI/4.0d);
//                tTr[1]=Math.sin(Math.PI/4.0d);
//                tTr[2]=-tTr[1];
//                tTr[3]=tTr[0];
////                tTr[4]=x*(1-tTr[0])+y*tTr[1];
////                tTr[5]=-x*tTr[1]+y*(1-tTr[0]);
//            }
//            tTr[4]=x;
//            tTr[5]=y;
//            gD.setTransform(tTr);<<<<<<<<<< Not supported on WinCE
//        } else {
        gD.translate(x,y);
//        }
        if(rotByPI_4) {
            gD.drawPolygon(tXPt2,tYPt2,tXPt2.length);
        }else{
            gD.drawPolygon(tXPt,tYPt,tXPt.length);
        }
        gD.free();
    }
    
    /**
     * Register a new reference point.
     */
    public void registerNewRefPoint(Point pt) {
//        CourseLogAppForm.dbgL.setLog("\nNewRefPoint("+pt.x+","+pt.y+")");
        getMyDlg().updateTracer(); // Check if tracer is there
        if(myDlg.execute()==Form.IDOK) {
            MapReferencePoint np=new MapReferencePoint();
            np.iX=pt.x;
            np.iY=pt.y;
            np.lat=myDlg.getLatitudeValue();
            np.lon=myDlg.getLongitudeValue();
            np.altSeaLevel=0.0d;
            
            cmMyMap.vRefPoints.add(np);
//            CourseLogAppForm.dbgL.addToLog("\n(lat,lon)=("+np.lat+","+np.lon+")");
            isMapModified=true;
        }
        stateReferenceDisplay=STATE_DISPLAYSIMPLE;
        updateDisplayedImage();
    }
    
// overidden methods
    
    /**
     * Modify the displayed image to draw reference points.
     */
    public void updateDisplayedImage() {
        super.updateDisplayedImage(null,0);
        if(stateReferenceDisplay==STATE_NODISPLAY) {
            return;
        }else{
            for(int idxRp=cmMyMap.vRefPoints.size()-1; idxRp>=0; idxRp--) {
                MapReferencePoint mrC= (MapReferencePoint) cmMyMap.vRefPoints.elementAt(idxRp);
                if((stateReferenceDisplay&STATE_DISPLAYDOUBLE)!=0) {
                    tmpPt=cmMyMap.getMapPointFromPosition(mrC,tmpGD,tmpPt);
                    tmpPt=baseToDisplay(tmpPt.x,tmpPt.y,tmpPt);
                    if((tmpPt.x>=-5)&&(tmpPt.x<=dispImage.getWidth()+5)&&
                            (tmpPt.y>=-5)&&(tmpPt.y<=dispImage.getHeight()+5)) {
                        currentPen=DUALPEN;
                        drawRefPointSymbolAt(dispImage,tmpPt.x,tmpPt.y,true);
                    }
                }
                tmpPt=baseToDisplay(mrC.iX,mrC.iY,tmpPt);
                if((tmpPt.x>=-5)&&(tmpPt.x<=dispImage.getWidth()+5)&&
                        (tmpPt.y>=-5)&&(tmpPt.y<=dispImage.getHeight()+5)) {
                    currentPen=NORMALPEN;
                    drawRefPointSymbolAt(dispImage,tmpPt.x,tmpPt.y);
                }
            }
        }
    }
    
    // Done echanger pen held et pen click entre detruire et ajouter pour coherence avec navigation
    
    /** Pen clickon the displayed image, display a dialog form to register
     * a new reference point.
     */
    public void actionOnPenClick(Point p) {
        tmpPt=displayToBase(p.x,p.y,tmpPt);
        mThread thPen=new mThread(new Runnable() {
            public void run() {
                registerNewRefPoint(tmpPt);
            }
        });
        thPen.start();
    }
    
    /**
     * Pen held, propose to delete closer reference point.
     */
    public void actionOnPenHeld(Point p) {
        tmpPt=displayToBase(p.x,p.y,tmpPt);
        mThread delThread=new mThread(new Runnable() {
            public void run() {
                tryDeleteReferencepoint(tmpPt);
            }
        });
        delThread.start();
    }
    
    /**
     * Long press on enter, consider the center is pointed as a reference point
     * if the reticule is displayed.
     */
    public void doublePressEnter(KeyEvent kEv) {
        if(isReticuleOn) {
            if(tmpPt==null) {
                tmpPt=new Point();
            }
            tmpPt.set(centerX,centerY);
            mThread thEnt=new mThread(new Runnable() {
                public void run() {
                    registerNewRefPoint(tmpPt);
                }
            });
            thEnt.start();
        }
    }
}
